/**
 * @author:albert
 */

package com.bkbw.live.battle.actor;

import java.lang.reflect.Method;
import java.security.KeyStore.Entry;
import java.sql.Time;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.badlogic.gdx.ai.GdxAI;
import com.bkbw.live.battle.net.client.DatabaseClient;
import com.bkbw.live.battle.net.codec.PackageHead;
import com.bkbw.live.battle.util.Vector3Helper;

import akka.actor.ActorRef;
import akka.actor.Cancellable;
import akka.actor.UntypedActor;
import akka.util.Duration;

import com.bkbw.live.battle.bean.BeanConvertor;
import com.bkbw.live.battle.bean.PlayerInDungeon;
import com.bkbw.live.battle.bean.UserAgent;
import com.bkbw.live.battle.business.BuildingObject;
import com.bkbw.live.battle.business.DistanceObject;
import com.bkbw.live.battle.business.GameLogicMap;
import com.bkbw.live.battle.business.GameObject;
import com.bkbw.live.battle.business.UnitObject;
import com.bkbw.live.battle.business.ai.AiState;
import com.bkbw.live.battle.business.items.UnitBagItem;
import com.bkbw.live.battle.business.items.UnitBagItemChange;
import com.bkbw.live.battle.business.items.UnitEquipment;
import com.bkbw.live.battle.business.items.UnitWeapon;
import com.bkbw.live.battle.database.DatabaseManager;
import com.bkbw.live.battle.database.bean.BagBeanManager;
import com.bkbw.live.battle.database.bean.DBodyEquipmentBean;
import com.bkbw.live.battle.database.bean.BagBeanManager.BagEquipmentBean;
import com.bkbw.live.battle.database.bean.BagBeanManager.BagItemBean;
import com.bkbw.live.battle.database.bean.BagBeanManager.BagWeaponBean;
import com.bkbw.live.common.GameConfig;
import com.bkbw.live.common.business.ItemTypeUtil;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.BS2DBBuyItemReq;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.BS2DBCharacterReq;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.BS2DBDropBagItemReq;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.BS2DBEquipReq;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.BS2DBSaveCharacterReq;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DB2BSBagItemDetailResp;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DB2BSBuyItemResp;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DB2BSCharacterResp;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DB2BSDropBagItemResp;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DB2BSEquipResp;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DB2BSUseBagItemResp;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DbBagEquipment;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DbBagItem;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DbBagWeapon;
import com.bkbw.live.common.dataproto.BattleToDatabasePb.DbBodyEquipment;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.AddMonsterNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.AttackNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CBagItemDetailResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CBuildMoveNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CBuildMoveResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CBuyItemResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CDropBagItemResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CEquipNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CEquipResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BS2CUseBagItemResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BagChangeStruct;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BagEquipment;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BagEquipmentBase;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BagItem;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BagWeapon;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildInfo;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildListNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildRemoveNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildRemoveReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildRemoveResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BuildResp;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BulletCreateNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BulletMoveNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.BulletRemoveNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.C2BSBagItemDetailReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.C2BSBuildMoveReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.C2BSBuyItemReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.C2BSDropBagItemReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.C2BSEquipReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.C2BSUseBagItemReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.CubeInfo;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.DamageNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.HeadType;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.LoginReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.Logout;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.MonsterInfoPb;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.Move;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.MoveDataPb;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.MoveEntityTypePb;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.MoveNotify;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.MoveStateChange;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.PlayerDetailInfo;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.PlayerInfo;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.UserSetAttackTargetReq;
import com.bkbw.live.common.dataproto.ClientToBattleServerPb.Vector3d;
import com.bkbw.live.common.dataproto.CommonMessagePb.BagItemChangePb;
import com.bkbw.live.common.dataproto.CommonMessagePb.DBagItemPb;
import com.bkbw.live.common.dataproto.CommonMessagePb.DCharacterPb;
import com.bkbw.live.common.dataproto.CommonMessagePb.HashLongInt;
import com.bkbw.live.common.dataproto.CommonMessagePb.NatureAttr;
import com.bkbw.live.common.dataproto.CommonMessagePb.TripleLongIntIntPb;
import com.bkbw.live.common.dataproto.EnumConfigPb.BuildType;
import com.bkbw.live.common.dataproto.EnumConfigPb.EquipType;
import com.bkbw.live.common.dataproto.EnumConfigPb.ResultCode;
import com.bkbw.live.common.util.Utils;
import com.bkbw.live.battle.net.message.MessageObject;

public class BattleActor extends UntypedActor{
	
	Logger logger = LoggerFactory.getLogger("mylog");
	
	private Cancellable cancel;
	private int tableid;//每个副本的id,这个值和每个用户的联盟id有关系
	//房间中的所有玩家列表
	private Map<Integer,UserAgent> map = new HashMap<Integer,UserAgent>();
	protected GameLogicMap gameMap = new GameLogicMap(this);
	
	public UserAgent getUserAgentByCharId(int charId) {
		if (map.containsKey(charId)) {
			return map.get(charId);
		}
		return null;
	}
	
	ActorRef manager;
	private int sessionId = 1;
	private int newSessionId() {
		return this.sessionId++;
	}
	private static class GameSession {
		Object param;
		long timeval;
	}
	private Map<Integer, SessionAction> sessionMap = new HashMap<Integer, SessionAction>();
	public static interface SessionAction {
		public void doAction(boolean timeout, Object param);
	}
	
	private float saveTime = 60.0f;
	private float saveTick = 0f;
	
	public void attackNotify(int id1, int id2)
	{
		AttackNotify.Builder builder = AttackNotify.newBuilder();
		builder.setId(id1);
		builder.setTargetId(id2);
		//builder.setUserId(uid1);
		//builder.setTargetUserId(uid2);
		AttackNotify attackNotify = builder.build();
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			player.getSession().write(attackNotify);
		}
	}
	
	public void damageNotify(int id1, int id2, int damage, int currentHp) 
	{
		DamageNotify.Builder builder = DamageNotify.newBuilder();
		builder.setId(id1);
		builder.setTargetId(id2);
		//builder.setUserId(uid1);
		//builder.setTargetUserId(uid2);
		builder.setDamage(damage);
		builder.setCurrentHp(currentHp);
		DamageNotify damageNotify = builder.build();
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			player.getSession().write(damageNotify);
		}
	}
	
	public void bulletCreateNotify(int bid, Vector3d pos, Vector3d head, float speed)
	{
		BulletCreateNotify.Builder builder = BulletCreateNotify.newBuilder();
		builder.setId(bid);
		builder.setPos(pos);
		builder.setSpeed(speed);
		builder.setHead(head);
		BulletCreateNotify bulletCreateNotify = builder.build();
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			player.getSession().write(bulletCreateNotify);
		}
	}
	
	public void bulletMoveNotify(int bid, Vector3d pos, Vector3d head, float speed)
	{
		BulletMoveNotify.Builder builder = BulletMoveNotify.newBuilder();
		builder.setId(bid);
		builder.setPos(pos);
		builder.setSpeed(speed);
		builder.setHead(head);
		BulletMoveNotify bulletMoveNotify = builder.build();
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			player.getSession().write(bulletMoveNotify);
		}
	}
	
	public void bulletRemoveNotify(int bid)
	{
		BulletRemoveNotify.Builder builder = BulletRemoveNotify.newBuilder();
		builder.setId(bid);
		BulletRemoveNotify bulletRemoveNotify = builder.build();
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			player.getSession().write(bulletRemoveNotify);
		}
	}
	
	public BattleActor(int tableid, ActorRef manager) {
		this.manager = manager;
		this.tableid = tableid;
		System.out.println("房间"+tableid+"启动");
		try {
			update();
		}
		catch (Exception e){
			e.printStackTrace();
		}
		
		//this.getContext().system().scheduler().schedule(Duration.Zero(), Duration.create(0, TimeUnit.MILLISECONDS),getSelf(), "loop");
	}
	
	private void sessionStart(int sessionId, int timeoutSec, SessionAction action) {
//		GameSession gameSession = new GameSession();
//		gameSession.param = param;
//		gameSession.timeval = System.currentTimeMillis();
//		sessionMap.put(this.session, gameSession);
//		SessionAction action = (boolean timeout) -> {
//			if (timeout) {
//				
//			}
//			else {
//				
//			}
//		};
		//this.getContext().system().scheduler().schedule(Duration.Zero(), Duration.create(timeoutSec, TimeUnit.SECONDS),getSelf(), "sessiontimeout_"+sessionId);
		sessionMap.put(sessionId, action);
		this.getContext().system().scheduler().scheduleOnce(Duration.create(timeoutSec, TimeUnit.SECONDS),getSelf(), "sessiontimeout_"+sessionId);
	}
	
	@Override
	public void onReceive(Object arg0) {
		//  it's better not throw exception to akka
		try {
			if (arg0 instanceof String) {
				String s = (String)arg0;
				if (s.startsWith("sessiontimeout_")) {
					logger.debug("session timeout");
					s = s.substring("sessiontimeout_".length());
					Integer sessionId = Integer.parseInt(s);
					
					// 超时了
					if (this.sessionMap.containsKey(sessionId)) {
						logger.debug("session timeout"+sessionId);	
						this.sessionMap.get(sessionId).doAction(true,null);
						this.sessionMap.remove(sessionId);
					}
					else {
						logger.debug("session processed " + this.sessionId);	
					}
				}
				else if("loop".equals(arg0)){
					//logger.debug("loop");
					update();
				}
				else if("stop".equals(arg0)){
					cancel.cancel();
					System.out.println("房间"+tableid+"停止");
				}
			}
			else if(arg0 instanceof MessageObject){
				long n1 = System.nanoTime();
				MessageObject mo = (MessageObject) arg0;
				switch (mo.getHead()) {
				case HeadType.DUNGON_LOGIN_REQ_VALUE:
					playerEnter(mo);
					break;
				case HeadType.DUNGON_PLAYER_MOVE_VALUE:	
					playerMove(mo);
					break;
				case HeadType.DUNGON_PLAYER_MOVE_STATE_CHANGE_VALUE:
					playerStateChange(mo);
					break;
				case HeadType.C2BS_BUILD_REQ_VALUE:
					buildRequest(mo);
					break;
				case HeadType.C2BS_BUILD_REMOVE_REQ_VALUE:
					buildRemoveReq(mo);
					break;
				case HeadType.USER_SET_ATTACKTARGET_REQ_VALUE:
					userSetAttackTargetReq(mo);
					break;
				case HeadType.DUNGON_LOGOUT_VALUE:
					playerLogout(mo);
					break;
				case com.bkbw.live.common.dataproto.BattleToDatabasePb.HeadType.DB2BS_CHARACTER_RESP_VALUE:
					onMsgDB2BSCharacterInfoResp(mo);
					break;
				case HeadType.C2BS_BAG_ITEM_DETAIL_REQ_VALUE:
					onMsgC2BSBagItemDetailReq(mo);
					break;
				case HeadType.C2BS_DROP_BAG_ITEM_REQ_VALUE:
					onMsgC2BSDropBagItemReq(mo);
					break;
				case com.bkbw.live.common.dataproto.BattleToDatabasePb.HeadType.DB2BS_DROP_BAG_ITEM_RESP_VALUE:
					onMsgDB2BSDropBagItemResp(mo);
					break;
				case HeadType.C2BS_USE_BAG_ITEM_REQ_VALUE:
					onMsgC2BSUseBagItemReq(mo);
					break;
				case com.bkbw.live.common.dataproto.BattleToDatabasePb.HeadType.DB2BS_USE_BAG_ITEM_RESP_VALUE:
					onMsgDB2BSUseBagItemResp(mo);
					break;
				case HeadType.C2BS_BUY_ITEM_REQ_VALUE:
					onMsgC2BSBuyItemReq(mo);
					break;
				case HeadType.C2BS_EQUIP_REQ_VALUE:
					onMsgC2BSEquipReq(mo);
					break;
				case com.bkbw.live.common.dataproto.BattleToDatabasePb.HeadType.DB2BS_BUY_ITEM_RESP_VALUE:
					onMsgDB2BSBuyItemResp(mo);
					break;
				case com.bkbw.live.common.dataproto.BattleToDatabasePb.HeadType.DB2BS_EQUIP_RESP_VALUE:
					onMsgDB2BSEquipResp(mo);
					break;
				case HeadType.C2BS_BUILD_MOVE_REQ_VALUE:
					onBuildMoveReq(mo);
					break;
				default:
					
					break;
				}
				long n2 = System.nanoTime();
				//logger.debug("process messageid " + mo.getHead() + " " + mo.getData().getClass() + " use time " + (n2 - n1) * 0.000000001);
			}
		}
		catch (Exception e){
			e.printStackTrace();
		}
		
	}
	


	/**
	 * 房间的主循环函数
	 */
	long lastMillis = 0;
	private void update(){
		//cancel = this.getContext().system().scheduler().scheduleOnce(Duration.create(25, TimeUnit.MICROSECONDS),getSelf(), "loop");
		
		//广播每个玩家的位置 
		//broadcast();
		
		long millis = System.currentTimeMillis();
		//System.out.println("update time diff " + (millis - lastMillis));
		lastMillis = millis;
		//gameMap.update(0.05f);
		gameMap.update(GdxAI.getTimepiece().getDeltaTime());
		broadcastNearUnit();
		//System.out.println("GdxAI.getTimepiece().getDeltaTime() " + GdxAI.getTimepiece().getDeltaTime());
		long millis2 = System.currentTimeMillis();
		
		// every 30 second save character
		saveTick += GdxAI.getTimepiece().getDeltaTime();
		if (saveTick >= saveTime) {
			Iterator<Integer> it = map.keySet().iterator();
			while(it.hasNext()){
				int id = it.next();
				UserAgent p = map.get(id);
				saveCharacter(p);
			}
			saveTick = 0f;
		}
		//System.out.println("update time use " + (millis2 - millis));
		//输出每个玩家的位置
		//printPlayerPos();
	}
	
	protected void broadcastNearBullet() {
		
	}
	
	/*
	 * 打包发送附近的玩家位置信息
	 */
	protected void broadcastNearUnit(){
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			if (player.getUnit() == null) {
				continue;
			}
			LinkedList<DistanceObject<UnitObject>> list = gameMap.getUnitsInDistance(player.getUnit(), GameConfig.AoiLen);
			if (list.size() <= 0) {
				continue;
			}
			//System.out.println("near unit count "+list.size());
			MoveNotify mn = null;
			MoveNotify.Builder mb = MoveNotify.newBuilder();
			boolean isMoving = player.getUnit().isMoving();
			for(DistanceObject<UnitObject> distanceObject : list) {
				UnitObject unitObject = distanceObject.getGameObject();
				if (unitObject.getId() == player.getUnit().getId()) {
					continue;
				}
				
				if (!isMoving && !unitObject.isMoving()) {
					continue;
				}
				
				MoveDataPb.Builder pmd = MoveDataPb.newBuilder();
				pmd.setId(unitObject.getId());
				if (unitObject.isMonster()) {
					pmd.setMoveEntityType(MoveEntityTypePb.MoveEntityType_Monster);
				}
				else {
					pmd.setMoveEntityType(MoveEntityTypePb.MoveEntityType_Player);
				}
				pmd.setPos(Vector3Helper.convertToDataprotoVector3(unitObject.getPosition()));
				//logger.debug("send id "+unitObject.getId()+ " movedata " + unitObject.getPosition());
				// 如果玩家在移动，则把周围所有单位信息发给他，包括没移动的单位
				// 因为玩家可能在移动中碰到没有移动的单位，也需要显示
				if (isMoving) {
					if (unitObject.isMoving()) {
						pmd.setState(1);
					}
					else {
						pmd.setState(0);
					}
				}
				// 如果玩家自己没有移动，则没有必要把周围静止的单位信息发给它，只需要把周围在移动的单位信息发给它
				else {
					if (unitObject.isMoving()) {
						pmd.setState(1);
					}
				}
				mb.addList(pmd.build());
			}
			
			mn = mb.build();
			
			if (mn.getListCount() > 0) {
				player.getSession().write(mn);
				//logger.debug(mn.toString());
			}
		}
	}
	
	// 把状态改变的单位信息广播给所有玩家
	public void unitMoveStateChange(int unitId, int move) {
		UnitObject currentUnit = gameMap.getUnitObjectById(unitId);
		if (currentUnit == null) {
			return;
		}
		//LinkedList<DistanceObject<UnitObject>> list = gameMap.getUnitsInDistance(currentUnit, GameConfig.AoiLen);
		LinkedList<DistanceObject<UnitObject>> list = gameMap.getAllUnits(currentUnit);
		
		/*currentUnit.setMoving(move==1?true:false);
		if (move == 1) {
			currentUnit.setTargetEnemy(null);
		}*/
		
		boolean isMoving = (move == 1 ? true : false);
		for(DistanceObject<UnitObject> distanceObject : list) {
			UnitObject unitObject = distanceObject.getGameObject();
			if (unitId == unitObject.getId()) {
				continue;
			}
			if (!unitObject.isUserControl()) {
				continue;
			}
			if (unitObject.getAgent() == null) {
				continue;
			}
			
			MoveNotify mn = null;
			MoveNotify.Builder mb = MoveNotify.newBuilder();
			
	
			MoveDataPb.Builder pmd = MoveDataPb.newBuilder();
			pmd.setId(currentUnit.getId());
			if (currentUnit.isMonster()) {
				pmd.setMoveEntityType(MoveEntityTypePb.MoveEntityType_Monster);
			}
			else {
				pmd.setMoveEntityType(MoveEntityTypePb.MoveEntityType_Player);
			}
			pmd.setPos(Vector3Helper.convertToDataprotoVector3(currentUnit.getPosition()));
			if (isMoving) {
				//logger.debug("id "+currentUnit.getId()+" state change start move " + currentUnit.getPosition());
				pmd.setState(1);
			}
			else {
				//logger.debug("id "+currentUnit.getId()+" state change stop move " + currentUnit.getPosition());
				pmd.setState(0);
			}
			mb.addList(pmd.build());
			mn = mb.build();
			if (mn.getListCount() > 0) {
				unitObject.getAgent().getSession().write(mn);
				//logger.debug("movestatechange"+mn.toString());
			}
		}
	}	
	
	private void printPlayerPos() {
		// TODO Auto-generated method stub
		String sb = "";
		for(Map.Entry<Integer, UserAgent> en:map.entrySet()){
			sb+=("id:"+en.getKey()+" state:"+en.getValue().getUnit().getState()+" pos:"+en.getValue().getUnit().getPosition()+"||");
		}
		System.out.println(sb);
	}
	
	public void broadcastMonsterEnter(UnitObject robot) {
		AddMonsterNotify.Builder builder = AddMonsterNotify.newBuilder();
		MonsterInfoPb.Builder monsterBuilder = MonsterInfoPb.newBuilder();
		monsterBuilder.setGameId(robot.getId());
		monsterBuilder.setRoleId(robot.getRoleId());
		monsterBuilder.setPos(Vector3Helper.convertToDataprotoVector3(robot.getPosition()));
		NatureAttr.Builder natureBuilder = NatureAttr.newBuilder();
		natureBuilder.setCurrentHp(robot.getCurrentHp());
		natureBuilder.setMaxHp(robot.getFinalHp());
		natureBuilder.setSpeed(robot.getSpeedLen());
		natureBuilder.setAttackRange(robot.getAttackRange());
		natureBuilder.setSight(robot.getSight());
		monsterBuilder.setNature(natureBuilder.build());
		builder.addMonster(monsterBuilder.build());
		AddMonsterNotify notify = builder.build();
		Iterator<Integer> it2  = map.keySet().iterator();
		while(it2.hasNext()){
			int id = it2.next();
			UserAgent p = map.get(id);
			
			
//			ClientToBattleServerPb.LoginNotify.Builder builder = ClientToBattleServerPb.LoginNotify.newBuilder();
//			ClientToBattleServerPb.PlayerInfo.Builder infobuilder = ClientToBattleServerPb.PlayerInfo.newBuilder();
//			//infobuilder.setId(req.getId());
//			infobuilder.setRoleId(robot.getRoleId());
//			infobuilder.setId(robot.getId());
//			infobuilder.setName("robot");
//			infobuilder.setPos(Vector3Helper.convertToDataprotoVector3(robot.getPosition()));
//			builder.setInfo(infobuilder.build());
			p.getSession().write(notify);
			
		}
	}
	
	
		
	// ----------------- message from client ----------------------------
	
	private void onMsgC2BSBagItemDetailReq(MessageObject mo) {
		BS2CBagItemDetailResp.Builder respBuilder = BS2CBagItemDetailResp.newBuilder();
		
		try {
			C2BSBagItemDetailReq req = (C2BSBagItemDetailReq)mo.getData();
			UserAgent agent = gameMap.getUserAgent(req.getId());
			BagItem bagItem = BeanConvertor.doTransUnitBagItem2BagItem(agent.getUnit().getBag().getUnitBagItemByUid(req.getUid()));
			
			
			if (bagItem != null) {
				respBuilder.setResult(ResultCode.Succeed);
				respBuilder.setBagItem(bagItem);
			}
			else {
				respBuilder.setResult(ResultCode.Failed);
			}
			
			mo.getSession().write(respBuilder.build());
			
			logger.debug("sendBagItemDetailResp");
		}
		catch (Exception e){
			e.printStackTrace();
			respBuilder.setResult(ResultCode.Failed);
			respBuilder.setDescription(Utils.exceptionStack(e));
			
		}
		finally {
			mo.getSession().write(respBuilder.build());
		}
		
	}
	
	private void onMsgC2BSDropBagItemReq(MessageObject mo) {
		BS2CDropBagItemResp.Builder respBuilder = BS2CDropBagItemResp.newBuilder();
		try {
			C2BSDropBagItemReq req = (C2BSDropBagItemReq)mo.getData();
			UserAgent agent = gameMap.getUserAgent(req.getId());
			List<UnitBagItemChange> unitBagItemChanges = agent.getUnit().getBag().dropUnitBagItemRetBagItem(req.getDropItemsList());
			List<BagItemChangePb> bagItemChangePbs = BeanConvertor.transUnitBagItemChange2BagItemChangePb(unitBagItemChanges);
			List<BagItem> bagItems = new LinkedList<BagItem>();
			for (BagItemChangePb bagItemChangePb : bagItemChangePbs) {
				bagItems.add(BeanConvertor.transDBagItemPb2BagItem(bagItemChangePb.getBagItem()));
			}
			
			
			DatabaseManager.getInstance().sendDbDropBagItemReq(req.getTableId(), agent.getCharId(), 0, bagItemChangePbs);
			//logger.debug("sendDbDropBagItemReq");
			
			BagChangeStruct.Builder structBuilder = BagChangeStruct.newBuilder();
			structBuilder.addAllBagItems(bagItems);
			respBuilder.setResult(ResultCode.Succeed);
			respBuilder.setBagChangeStruct(structBuilder.build());
			logger.debug("charId " + agent.getCharId() + " drop item "+req.getDropItemsList());
			
		}
		catch (Exception e) {
			respBuilder.setResult(ResultCode.Failed);
			respBuilder.setDescription(Utils.exceptionStack(e));
		}
		finally {
			mo.getSession().write(respBuilder.build());
		}
	}
	
	private void onMsgC2BSUseBagItemReq(MessageObject mo) {
		BS2CUseBagItemResp.Builder respBuilder = BS2CUseBagItemResp.newBuilder();
		try {
			C2BSUseBagItemReq req = (C2BSUseBagItemReq)mo.getData();
			UserAgent agent = gameMap.getUserAgent(req.getId());
			
			List<UnitBagItemChange> unitBagItemChanges = agent.getUnit().getBag().useUnitBagItemRetBagItem(req.getUseItemsList());
			List<BagItemChangePb> bagItemChangePbs = BeanConvertor.transUnitBagItemChange2BagItemChangePb(unitBagItemChanges);
			List<BagItem> bagItems = new LinkedList<BagItem>();
			for (BagItemChangePb bagItemChangePb : bagItemChangePbs) {
				bagItems.add(BeanConvertor.transDBagItemPb2BagItem(bagItemChangePb.getBagItem()));
			}
			
			DatabaseManager.getInstance().sendDbUseBagItemReq(req.getTableId(), agent.getCharId(), 0, bagItemChangePbs);
			logger.debug("sendDbUseBagItemReq");
			
			BagChangeStruct.Builder structBuilder = BagChangeStruct.newBuilder();
			structBuilder.addAllBagItems(bagItems);
			respBuilder.setResult(ResultCode.Succeed);
			respBuilder.setBagChangeStruct(structBuilder.build());
			logger.debug("charId " + agent.getCharId() + " use item "+req.getUseItemsList());
		}
		catch (Exception e){
			respBuilder.setResult(ResultCode.Failed);
			respBuilder.setDescription(Utils.exceptionStack(e));
		}
		finally {
			mo.getSession().write(respBuilder.build());
		}
		
		
	}
	
	//onMsgC2BSBuyItemReq
	private void onMsgC2BSBuyItemReq(MessageObject mo) {
		try {
			C2BSBuyItemReq req = (C2BSBuyItemReq)mo.getData();
			UserAgent agent = gameMap.getUserAgent(req.getId());
			
			List<UnitBagItemChange> unitBagItemChanges = agent.getUnit().getBag().addNewUnitBagItemRetBagItem(req.getBuyItems());
			List<BagItemChangePb> bagItemChangePbs = BeanConvertor.transUnitBagItemChange2BagItemChangePb(unitBagItemChanges);
			List<BagItem> bagItems = new LinkedList<BagItem>();
			for (BagItemChangePb bagItemChangePb : bagItemChangePbs) {
				bagItems.add(BeanConvertor.transDBagItemPb2BagItem(bagItemChangePb.getBagItem()));
			}
	
			// 
//			SessionAction action = (boolean timeout, Object param) -> {
//				logger.debug(timeout?"action with timeout":"action with msg");
//				if (timeout) {
//					
//				}
//				else {
//					
//				}
//			};
			
			BS2DBBuyItemReq.Builder buyBuilder = BS2DBBuyItemReq.newBuilder();
			buyBuilder.setCharId(agent.getCharId());
			buyBuilder.setTableId(req.getTableId());
			buyBuilder.addAllBuyItems(bagItemChangePbs);
			BS2DBBuyItemReq buyReq = buyBuilder.build();
			
			DatabaseManager.getInstance().sendDbBuyItemReq(buyReq);
			
			BS2CBuyItemResp.Builder respBuilder = BS2CBuyItemResp.newBuilder();
			BagChangeStruct.Builder structBuilder = BagChangeStruct.newBuilder();
			structBuilder.addAllBagItems(bagItems);
			respBuilder.setResult(ResultCode.Succeed);
			respBuilder.setBagChangeStruct(structBuilder.build());
			//respBuilder.setHeadType(HeadType.BS2C_BUY_ITEM_RESP);
			mo.getSession().write(respBuilder.build());
			//int sessionId = newSessionId();
			//DatabaseManager.getInstance().sendDbUseBagItemReq(req.getTableId(), agent.getCharId(), sessionId, req.getUseItemsList());
			//sessionStart(sessionId, 10, action);
			logger.debug("charId " + agent.getCharId() + " use item "+req.getBuyItems());
			
		}
		catch (Exception e){
			e.printStackTrace();
		}
		
		
	}
	
	
	private void onMsgC2BSEquipReq(MessageObject mo) {
		try {
			C2BSEquipReq req = (C2BSEquipReq)mo.getData();
			UserAgent agent = gameMap.getUserAgent(req.getId());
			
			List<UnitBagItemChange> unitBagItemChanges = agent.getUnit().getBag().putonEquipment(req.getUid());
			List<BagItemChangePb> bagItemChangePbs = BeanConvertor.transUnitBagItemChange2BagItemChangePb(unitBagItemChanges);
			List<BagItem> bagItems = new LinkedList<BagItem>();
			List<DBagItemPb> bagItemPbs = new LinkedList<DBagItemPb>();
			for (BagItemChangePb bagItemChangePb : bagItemChangePbs) {
				bagItems.add(BeanConvertor.transDBagItemPb2BagItem(bagItemChangePb.getBagItem()));
				bagItemPbs.add(bagItemChangePb.getBagItem());
			}
			// TODO: session
//			SessionAction action = (boolean timeout, Object param) -> {
//				logger.debug(timeout?"action with timeout":"action with msg");
//				if (timeout) {
//					
//				}
//				else {
//					
//				}
//			};
			DbBodyEquipment.Builder onBodyEquipmentBuilder = DbBodyEquipment.newBuilder();
			DBodyEquipmentBean bean = agent.getUnit().getBag().getOnBodyEquipmentToDbBodyEquipment();
			Utils.copyFieldsToBean(bean, onBodyEquipmentBuilder);
		
			BS2DBEquipReq.Builder equipBuilder = BS2DBEquipReq.newBuilder();
			equipBuilder.setCharId(agent.getCharId());
			equipBuilder.setTableId(req.getTableId());
			equipBuilder.addAllEquipItems(bagItemChangePbs);
			equipBuilder.setOnBodyEquipment(onBodyEquipmentBuilder.build());
			BS2DBEquipReq equipReq = equipBuilder.build();
			
			DatabaseManager.getInstance().sendDbEquipReq(equipReq);
			
			BS2CEquipResp.Builder respBuilder = BS2CEquipResp.newBuilder();
			BagChangeStruct.Builder structBuilder = BagChangeStruct.newBuilder();
			structBuilder.addAllBagItems(bagItems);
			respBuilder.setResult(ResultCode.Succeed);
			respBuilder.setBagChangeStruct(structBuilder.build());
			//respBuilder.setHeadType(HeadType.BS2C_EQUIP_RESP);
			mo.getSession().write(respBuilder.build());
			//int sessionId = newSessionId();
			
			BS2CEquipNotify.Builder equipNotifyBuilder = BS2CEquipNotify.newBuilder();
			equipNotifyBuilder.setCharGameId(req.getId());
			equipNotifyBuilder.addAllBagItem(bagItemPbs);
			BS2CEquipNotify notify = equipNotifyBuilder.build();
			Iterator<Integer> it = map.keySet().iterator();
			while(it.hasNext()){
				int id = it.next();
				UserAgent other = map.get(id);
				// 其他玩家信息不必包含自己
				if (other.getCharId() == agent.getCharId()) 
					continue;
				
				other.getSession().write(notify);
			}
			logger.debug("charId " + agent.getCharId() + " equip item "+req.getUid());
			for (DBagItemPb dBagItemPb : bagItemPbs) {
				logger.debug("itemid "+dBagItemPb.getItemId()+" isEquip "+dBagItemPb.getIsEquip());
			}
			//sessionStart(sessionId, 10, action);
		}
		catch (Exception e){
			e.printStackTrace();
		}
	}
	
	// ---------------- message from database server ------------------
		
	private void onMsgDB2BSCharacterInfoResp(MessageObject mo) {
		logger.debug("receive onMsgDB2BSCharacterInfoResp");
		DB2BSCharacterResp resp = (DB2BSCharacterResp)mo.getData();
		int sessionId = resp.getSessionId();
		if (this.sessionMap.containsKey(sessionId)) {
			this.sessionMap.get(sessionId).doAction(false, mo);
			this.sessionMap.remove(sessionId);
		}
	}
	
	private void onMsgDB2BSDropBagItemResp(MessageObject mo) {
		logger.debug("receive onMsgDB2BSDropBagItemResp");
		DB2BSDropBagItemResp resp = (DB2BSDropBagItemResp)mo.getData();
		logger.debug("charid " + resp.getCharId() + " drop items "+resp.getResult());
		int sessionId = resp.getSessionId();
		if (this.sessionMap.containsKey(sessionId)) {
			this.sessionMap.get(sessionId).doAction(false, mo);
			this.sessionMap.remove(sessionId);
		}
	}
	
	private void onMsgDB2BSUseBagItemResp(MessageObject mo){
		//logger.debug("receive onMsgDB2BSUseBagItemResp");
		DB2BSUseBagItemResp resp = (DB2BSUseBagItemResp)mo.getData();
		logger.debug("onMsgDB2BSUseBagItemResp charid " + resp.getCharId() + " use items "+resp.getResult());
		int sessionId = resp.getSessionId();
		if (this.sessionMap.containsKey(sessionId)) {
			this.sessionMap.get(sessionId).doAction(false, mo);
			this.sessionMap.remove(sessionId);
		}
	}
	
	
	private void onMsgDB2BSBuyItemResp(MessageObject mo){
		//logger.debug("receive onMsgDB2BSBuyItemResp");
		DB2BSBuyItemResp resp = (DB2BSBuyItemResp)mo.getData();
		//DB2BSUseBagItemResp resp = (DB2BSUseBagItemResp)mo.getData();
		logger.debug("onMsgDB2BSBuyItemResp charid " + resp.getCharId() + " buy items "+resp.getResult());
		
	}
	
	
	private void onMsgDB2BSEquipResp(MessageObject mo){
		//logger.debug("receive onMsgDB2BSEquipResp");
		DB2BSEquipResp resp = (DB2BSEquipResp)mo.getData();
		//DB2BSUseBagItemResp resp = (DB2BSUseBagItemResp)mo.getData();
		logger.debug("onMsgDB2BSEquipResp charid " + resp.getCharId() + " equip items "+resp.getResult());
		
	}
	// ----------------- message from client ------------------

	private void playerEnter(MessageObject mo){
		ClientToBattleServerPb.LoginReq req  = (LoginReq) mo.getData();
		
		if (map.containsKey(req.getUserId())) {
			ClientToBattleServerPb.LoginResp.Builder resBuilder = ClientToBattleServerPb.LoginResp.newBuilder();
			resBuilder.setError(1);//存在错误
			resBuilder.setDescription("uid为"+req.getUserId()+"的玩家已经存在");
			mo.getSession().write(resBuilder.build());
			return;
		}
		//创建一个玩家对象
		UserAgent player = new UserAgent(mo.getSession(),req.getUserId(),req.getName());
		map.put(player.getCharId(), player);
		
		
		SessionAction action = (boolean timeout, Object param) -> {
			logger.debug(timeout?"action with timeout":"action with msg");
			if (timeout) {
				ClientToBattleServerPb.LoginResp.Builder resBuilder = ClientToBattleServerPb.LoginResp.newBuilder();
				resBuilder.setError(1);//存在错误
				resBuilder.setDescription("request to db timeout");
				logger.debug("timeout");
				mo.getSession().write(resBuilder.build());
			}
			else {
				MessageObject messageObject = (MessageObject)param;
				DB2BSCharacterResp charResp = (DB2BSCharacterResp)messageObject.getData();
				try {
					if (charResp.getResult() == ResultCode.Succeed) {
						ClientToBattleServerPb.LoginResp.Builder resBuilder = ClientToBattleServerPb.LoginResp.newBuilder();
						gameMap.createPlayerByUser(player);
						ClientToBattleServerPb.Vector3d.Builder v3dBuilder = ClientToBattleServerPb.Vector3d.newBuilder();
						v3dBuilder.setX(47);
						v3dBuilder.setY(0);
						v3dBuilder.setZ(41);
						player.getUnit().setPosition(Vector3Helper.convertToApacheVector3(v3dBuilder.build()));
						logger.debug("charId "+player.getCharId()+" login");
						//返回登陆结果
						//ClientToBattleServerPb.LoginResp.Builder resBuilder = ClientToBattleServerPb.LoginResp.newBuilder();
						//是否重复连接
						//if(map.containsKey(player.getUid())){
//						if(map.containsKey(player.getCharId())){
//							resBuilder.setError(1);//存在错误
//							resBuilder.setDescription("uid为"+player.getCharId()+"的玩家已经存在");
//							return;
//						}
						resBuilder.setError(0);//登陆成功
						resBuilder.setDescription("ok");
						resBuilder.setTableId(tableid);
						
						ClientToBattleServerPb.PlayerInfo.Builder infoBuilder = ClientToBattleServerPb.PlayerInfo.newBuilder();
						//ClientToBattleServerPb.Vector3d.Builder v3dBuilder = ClientToBattleServerPb.Vector3d.newBuilder()
//						v3dBuilder.setX(1);
//						v3dBuilder.setY(0);
//						v3dBuilder.setZ(1);
						infoBuilder.setPos(v3dBuilder.build());
						infoBuilder.setName("name");
						//infoBuilder.setId(req.getId());
						infoBuilder.setId(player.getUnit().getId());
						infoBuilder.setRoleId(player.getUnit().getRoleId());
						
						
						// player detail info
						PlayerDetailInfo.Builder playerDetailInfoBuilder = PlayerDetailInfo.newBuilder();
						
						if (charResp.hasDbCharacterInfo()) {
							NatureAttr.Builder natureBuilder = NatureAttr.newBuilder();
							DCharacterPb dbCharacterInfo = charResp.getDbCharacterInfo();
							natureBuilder.setCurrentHp(dbCharacterInfo.getCurrentHp());
							infoBuilder.setHp(dbCharacterInfo.getCurrentHp());
							natureBuilder.setMaxHp(dbCharacterInfo.getMaxHp());
							natureBuilder.setAttack(0);
							natureBuilder.setEvade(dbCharacterInfo.getEvade());
							natureBuilder.setSpeed(player.getUnit().getSpeedLen());
							natureBuilder.setAttackRange(player.getUnit().getAttackRange());
							natureBuilder.setSight(player.getUnit().getSight());
							player.setUidSeed(dbCharacterInfo.getItemUidSeed());
							playerDetailInfoBuilder.setNature(natureBuilder.build());
							
							player.getUnit().getBaseNature().setCurrentHp(dbCharacterInfo.getCurrentHp());
							player.getUnit().getBaseNature().setMaxHp(dbCharacterInfo.getMaxHp());
							player.getUnit().getBaseNature().setEvade(dbCharacterInfo.getEvade());
						}
						
						infoBuilder.setDetail(playerDetailInfoBuilder.build());
						
						
						UnitObject thisUnit = player.getUnit();
						
						// player bag info, include item, equipment, weapon
						if (charResp.getBagItemCount() > 0) {
							BagItem.Builder bagItemBuilder = BagItem.newBuilder();
							for (DbBagItem dbBagItem : charResp.getBagItemList()) {
								resBuilder.addBagInfo(BeanConvertor.dbBagItem2BagItem(dbBagItem));
								UnitBagItem unitBagItem = BeanConvertor.transDbBagItem2UnitBagItem(dbBagItem);
								thisUnit.getBag().loadUnitBagItem(unitBagItem);
//								if (unitBagItem != null) {
//									thisUnit.getBag().loadUnitBagItem(unitBagItem);
//								}
//								else {
//									logger.debug("transDbBagItem2UnitBagItem fail");
//									Utils.dumpObject(dbBagItem);
//								}
								
							}
						}
						if (charResp.getBagEquipmentCount() > 0) {
							BagItem.Builder bagItemBuilder = BagItem.newBuilder();
							for (DbBagEquipment dbBagEquipment : charResp.getBagEquipmentList()) {
								
								resBuilder.addBagInfo(BeanConvertor.dbBagEquipment2BagItem(dbBagEquipment));
								UnitEquipment unitEquipment = BeanConvertor.transDbBagEquipment2UnitEquipment(dbBagEquipment);
								BagEquipmentBean bagEquipmentBean = BagBeanManager.getInstance().getBagEquipmentBeanById(unitEquipment.getItemId());
								//unitEquipment.setEquipType(bagEquipmentBean.getEquipType());
								thisUnit.getBag().loadUnitBagItem(unitEquipment);
							}
						}
						if (charResp.getBagWeaponCount() > 0) {
							BagItem.Builder bagItemBuilder = BagItem.newBuilder();
							for (DbBagWeapon dbBagWeapon : charResp.getBagWeaponList()) {
								
								resBuilder.addBagInfo(BeanConvertor.dbBagWeapon2BagItem(dbBagWeapon));
								
								UnitWeapon unitWeapon = BeanConvertor.transDbBagWeapon2UnitWeapon(dbBagWeapon);
								BagWeaponBean bagWeaponBean = BagBeanManager.getInstance().getBagWeaponBeanById(unitWeapon.getItemId());
								//unitWeapon.setEquipType(bagWeaponBean.getEquipType());
								thisUnit.getBag().loadUnitBagItem(unitWeapon);
								
							}
						}
						
						if (charResp.hasDbBodyEquipment()) {
							DbBodyEquipment dbBodyEquipment = charResp.getDbBodyEquipment();
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getHeadUid());
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getMaskUid());
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getClothUid());
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getLeftHandUid());
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getRightHandUid());
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getShoeUid());
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getRingUid());
//							infoBuilder.addBodyEquipmentUids(dbBodyEquipment.getNeckUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.HeadUid_VALUE, dbBodyEquipment.getHeadUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.MaskUid_VALUE, dbBodyEquipment.getMaskUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.ClothUid_VALUE, dbBodyEquipment.getClothUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.LeftHandUid_VALUE, dbBodyEquipment.getLeftHandUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.RightHandUid_VALUE, dbBodyEquipment.getRightHandUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.ShoeUid_VALUE, dbBodyEquipment.getShoeUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.RingUid_VALUE, dbBodyEquipment.getRingUid());
//							infoBuilder.setBodyEquipmentUids(BodyEquipmentUidIndex.NeckUid_VALUE, dbBodyEquipment.getNeckUid());
							for (int i = 1; i <= EquipType.DoubleShield_VALUE; ++i){
								EquipType type = EquipType.valueOf(i);
								String typeName = type.toString();
								Method method = null;
								try {
									method = dbBodyEquipment.getClass().getMethod("get"+typeName+"Uid");
									Object object = method.invoke(dbBodyEquipment);
									long uid = (long)object;
									if (uid == 0) {
										continue;
									}
									thisUnit.getBag().loadEquipment(type, uid);
								}
								catch (Exception e){
									e.printStackTrace();
								}
							}
							
							List<DBagItemPb> pblist = thisUnit.getBag().getOnBodyEquipmentToDBagItemPbs();
							if (pblist.size() > 0) {
								infoBuilder.addAllBodyEquipments(pblist);
							}
						}
						
						resBuilder.setSelf(infoBuilder.build());
						
						//组装其他玩家信息
						Iterator<Integer> it = map.keySet().iterator();
						while(it.hasNext()){
							int id = it.next();
							UserAgent other = map.get(id);
							// 其他玩家信息不必包含自己
							if (other.getCharId() == player.getCharId()) 
								continue;
							ClientToBattleServerPb.PlayerInfo.Builder ppb = ClientToBattleServerPb.PlayerInfo.newBuilder();
							ppb.setId(other.getUnit().getId());
							ppb.setRoleId(other.getUnit().getRoleId());
							ppb.setName(other.getUsername());
							ppb.setHp(other.getUnit().getCurrentHp());
							ppb.setPos(Vector3Helper.convertToDataprotoVector3(other.getUnit().getPosition()));
							PlayerDetailInfo.Builder playerDetailInfoBuilder2 = PlayerDetailInfo.newBuilder();
							NatureAttr.Builder natureBuilder = NatureAttr.newBuilder();
							natureBuilder.setCurrentHp(other.getUnit().getCurrentHp());
							infoBuilder.setHp(other.getUnit().getCurrentHp());
							natureBuilder.setMaxHp(other.getUnit().getFinalHp());
							natureBuilder.setSpeed(other.getUnit().getSpeedLen());
							natureBuilder.setAttackRange(other.getUnit().getAttackRange());
							natureBuilder.setSight(other.getUnit().getSight());
							playerDetailInfoBuilder2.setNature(natureBuilder.build());
							ppb.setDetail(playerDetailInfoBuilder2.build());
							
							List<DBagItemPb> pblist = other.getUnit().getBag().getOnBodyEquipmentToDBagItemPbs();
							if (pblist.size() > 0) {
								ppb.addAllBodyEquipments(pblist);
							}
							resBuilder.addOthers(ppb.build());
						}
						
						// 怪物信息
						for (UnitObject unitObject : this.gameMap.getAllUnitObject()) {
							
							if (unitObject.isMonster()) {
								MonsterInfoPb.Builder monsterBuilder = MonsterInfoPb.newBuilder();
								monsterBuilder.setGameId(unitObject.getId());
								monsterBuilder.setRoleId(unitObject.getRoleId());
								monsterBuilder.setPos(Vector3Helper.convertToDataprotoVector3(unitObject.getPosition()));
								NatureAttr.Builder natureBuilder = NatureAttr.newBuilder();
								natureBuilder.setCurrentHp(unitObject.getCurrentHp());
								natureBuilder.setMaxHp(unitObject.getFinalHp());
								natureBuilder.setSpeed(unitObject.getSpeedLen());

								natureBuilder.setAttackRange(unitObject.getAttackRange());
								natureBuilder.setSight(unitObject.getSight());
								monsterBuilder.setNature(natureBuilder.build());
								
								resBuilder.addMonsters(monsterBuilder.build());
//								PlayerInfo.Builder playerInfoBuilder = PlayerInfo.newBuilder();
//								playerInfoBuilder.setId(unitObject.getId());
//								playerInfoBuilder.setRoleId(unitObject.getRoleId());
//								playerInfoBuilder.setName("");
//								playerInfoBuilder.setPos(Vector3Helper.convertToDataprotoVector3(unitObject.getPosition()));
//								resBuilder.addOthers(playerInfoBuilder.build());
							}
							
						}
						
						
						//组装地图信息
						for(int i=0;i<5;i++){
							CubeInfo.Builder cb = CubeInfo.newBuilder();
							Vector3d.Builder cbpos = Vector3d.newBuilder();
							cbpos.setX((float) (1.25+i*0.5));
							cbpos.setY(0);
							cbpos.setZ((float) (2.25+i*0.5));
							cb.setPos(cbpos);
							cb.setSize(0.5f);
							resBuilder.addCube(cb);
						}
						
						//BuildListNotify.Builder buildListBuilder = BuildListNotify.newBuilder();
						for (BuildingObject buildingObject : gameMap.getBuildingList()) {
							BuildInfo.Builder buildInfoBuilder = BuildInfo.newBuilder();
							buildInfoBuilder.setBuildGameId(buildingObject.getId());
							buildInfoBuilder.setBuildingId(buildingObject.getBuildId());
							buildInfoBuilder.setPos(buildingObject.getVector3IntPbPos());
							resBuilder.addBuildList(buildInfoBuilder.build());
							//buildListBuilder.addBuildList(buildInfoBuilder.build());
						}
						
						// 把登陆响应发给刚登陆的玩家，包括已登陆玩家信息，当前地图上的建筑信息等
						mo.getSession().write(resBuilder.build());
						//mo.getSession().write(buildListBuilder.build());
						//告知房间内的所有玩家这个玩家来了
						Iterator<Integer> it2  = map.keySet().iterator();
						while(it2.hasNext()){
							int id = it2.next();
							UserAgent p = map.get(id);
							//自己不给自己发notify
							if (p.getCharId() == player.getCharId()) 
								continue;
							ClientToBattleServerPb.LoginNotify.Builder builder = ClientToBattleServerPb.LoginNotify.newBuilder();
							
							builder.setInfo(infoBuilder.build());
							p.getSession().write(builder.build());
							
						}
						logger.debug("charId "+player.getCharId()+" send LoginResp");
						//保存到房间数组中 
						//map.put(req.getId(), player);
						//mo.getSession().write(resBuilder.build());
					}
					else {
						ClientToBattleServerPb.LoginResp.Builder resBuilder = ClientToBattleServerPb.LoginResp.newBuilder();
						resBuilder.setError(1);//存在错误
						resBuilder.setDescription("db error");
						mo.getSession().write(resBuilder.build());
						logger.debug("send db error");
					}
				}
				catch (Exception e) {
					ClientToBattleServerPb.LoginResp.Builder resBuilder = ClientToBattleServerPb.LoginResp.newBuilder();
					resBuilder.setError(1);//存在错误
					resBuilder.setDescription(Utils.exceptionStack(e));
					mo.getSession().write(resBuilder.build());
					logger.debug("exception " + Utils.exceptionStack(e));
					e.printStackTrace();
				}
				
			}
		};
		int sessionId = newSessionId();
		//DatabaseClient.getInstance().requestCharacterInfo(this.tableid, req.getUserId(), sessionId);
		DatabaseManager.getInstance().sendDbCharacterReq(this.tableid, req.getUserId(), sessionId);
		sessionStart(sessionId, 10, action);
		logger.debug("requestCharacterInfo");
	}
	
	//处理玩家移动仅仅更新当前玩家位置
	private void playerMove(MessageObject mo){
		ClientToBattleServerPb.Move mov  = (Move) mo.getData();
		UnitObject unitObject = gameMap.getUnitObjectById(mov.getId());
		if (unitObject != null) {
			UserAgent agent = unitObject.getAgent();
			if (agent != null && map.containsKey(agent.getCharId())) {
				//unitObject.setPosition(Vector3Helper.convertToApacheVector3(mov.getPos()));
				gameMap.setObjectPosition(unitObject, Vector3Helper.convertToApacheVector3(mov.getPos()));
				
			}
		}
		
	}
	
	//玩家状态改变
	private void playerStateChange(MessageObject mo) {
		MoveStateChange m = (MoveStateChange) mo.getData();
		UnitObject unitObject = gameMap.getUnitObjectById(m.getId());
		if (unitObject != null) {
			UserAgent agent = unitObject.getAgent();
			if (agent != null && map.containsKey(agent.getCharId())) {
				if (m.getState() == 1) {
					unitObject.startMove();
				}
				else {
					unitObject.stopMove();
				}
			}
		}
	}
	
	
	private void buildRequest(MessageObject mo) {
		BuildReq buildReq = (BuildReq)mo.getData();
		UserAgent agent = null;
		UnitObject unitObject = gameMap.getUnitObjectById(buildReq.getCharGameId());
		if (unitObject != null) {
			agent = unitObject.getAgent();
			if (agent != null && map.containsKey(agent.getCharId())) {
				
			}
			else {
				return;
			}
		}
		logger.debug("charId "+buildReq.getCharGameId()+" request build with buildingId " + buildReq.getBuildingId());
		BuildResp.Builder respBuilder = BuildResp.newBuilder();
		BuildingObject buildingObject = gameMap.createBuildingByUser(buildReq.getCharGameId(), buildReq.getBuildingId(),buildReq.getPos());
		if (null == buildingObject) {
			respBuilder.setBuildGameId(0);
			respBuilder.setBuildingId(0);
			respBuilder.setError(1);
			respBuilder.setDescription("field is in use");
			agent.getSession().write(respBuilder.build());
		}
		else {
			respBuilder.setBuildGameId(buildingObject.getId());
			respBuilder.setBuildingId(buildReq.getBuildingId());
			respBuilder.setError(0);
			respBuilder.setDescription("");
			agent.getSession().write(respBuilder.build());
			
			BuildInfo.Builder buildInfoBuilder = BuildInfo.newBuilder();
			buildInfoBuilder.setBuildGameId(buildingObject.getId());
			buildInfoBuilder.setBuildingId(buildReq.getBuildingId());
			buildInfoBuilder.setPos(buildingObject.getBuildingPos());
			
			BuildNotify.Builder buildNotifyBuilder = BuildNotify.newBuilder();
			buildNotifyBuilder.setBuildInfo(buildInfoBuilder.build());
			BuildNotify buildNotify = buildNotifyBuilder.build();
			Iterator<Integer> it = map.keySet().iterator();
			while(it.hasNext()){
				int charId = it.next();
				UserAgent otherAgent = map.get(charId);
				UnitObject unit = otherAgent.getUnit();
				if (buildReq.getCharGameId() == unit.getId()) {
					continue;
				}
				otherAgent.getSession().write(buildNotify);
			}
		}
	}
	
	
	private void onBuildMoveReq(MessageObject mo) {
		C2BSBuildMoveReq buildReq = (C2BSBuildMoveReq)mo.getData();
		UserAgent agent = null;
		UnitObject unitObject = gameMap.getUnitObjectById(buildReq.getCharGameId());
		if (unitObject != null) {
			agent = unitObject.getAgent();
			if (agent != null && map.containsKey(agent.getCharId())) {
				
			}
			else {
				return;
			}
		}
		logger.debug("charId "+buildReq.getCharGameId()+" request move build buildGameId " + buildReq.getBuildGameId());
		BS2CBuildMoveResp.Builder respBuilder = BS2CBuildMoveResp.newBuilder();
		//TODO check user privilege
		boolean moveSucc = gameMap.moveBuild(buildReq.getBuildGameId(), buildReq.getPos());
		if (moveSucc) {
			respBuilder.setError(0);
			respBuilder.setBuildGameId(buildReq.getBuildGameId());
			respBuilder.setPos(buildReq.getPos());
			agent.getSession().write(respBuilder.build());
			
			BS2CBuildMoveNotify.Builder notifyBuilder = BS2CBuildMoveNotify.newBuilder();
			notifyBuilder.setBuildGameId(buildReq.getBuildGameId());
			notifyBuilder.setPos(buildReq.getPos());
			BS2CBuildMoveNotify notify = notifyBuilder.build();
			Iterator<Integer> it = map.keySet().iterator();
			while(it.hasNext()){
				int charId = it.next();
				UserAgent otherAgent = map.get(charId);
				UnitObject unit = otherAgent.getUnit();
				if (buildReq.getCharGameId() == unit.getId()) {
					continue;
				}
				otherAgent.getSession().write(notify);
			}
		}
		else {
			respBuilder.setError(1);
			respBuilder.setBuildGameId(buildReq.getBuildGameId());
			agent.getSession().write(respBuilder.build());
		}
		
		
	}
	
	public void mapBuildRemove(int removeId) {
		BuildRemoveNotify.Builder buildRemoveNotifyBuilder = BuildRemoveNotify.newBuilder();
		buildRemoveNotifyBuilder.setBuildGameId(removeId);
		BuildRemoveNotify buildRemoveNotify = buildRemoveNotifyBuilder.build();
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			player.getSession().write(buildRemoveNotify);
		}
	}
	
	private void buildRemoveReq(MessageObject mo) {
		BuildRemoveReq buildRemoveReq = (BuildRemoveReq)mo.getData();
		logger.debug("charId "+buildRemoveReq.getCharGameId()+" request remove buildGameId " + buildRemoveReq.getBuildGameId());
		if (gameMap.removeBuildingByUser(buildRemoveReq.getBuildGameId())) {
			BuildRemoveResp.Builder buildRemoveRespBuilder = BuildRemoveResp.newBuilder();
			buildRemoveRespBuilder.setError(0);
			buildRemoveRespBuilder.setDescription("");
			buildRemoveRespBuilder.setBuildGameId(buildRemoveReq.getBuildGameId());
			mo.getSession().write(buildRemoveRespBuilder.build());
			
			BuildRemoveNotify.Builder buildRemoveNotifyBuilder = BuildRemoveNotify.newBuilder();
			buildRemoveNotifyBuilder.setBuildGameId(buildRemoveReq.getBuildGameId());
			BuildRemoveNotify buildRemoveNotify = buildRemoveNotifyBuilder.build();
			Iterator<Integer> it = map.keySet().iterator();
			while(it.hasNext()){
				int charId = it.next();
				UserAgent otherAgent = map.get(charId);
				UnitObject unit = otherAgent.getUnit();
				if (buildRemoveReq.getCharGameId() == unit.getId()) {
					continue;
				}
				otherAgent.getSession().write(buildRemoveNotify);
			}
		}
		else {
			BuildRemoveResp.Builder buildRemoveRespBuilder = BuildRemoveResp.newBuilder();
			buildRemoveRespBuilder.setError(1);
			buildRemoveRespBuilder.setDescription("");
			buildRemoveRespBuilder.setBuildGameId(buildRemoveReq.getBuildGameId());
			mo.getSession().write(buildRemoveRespBuilder.build());
		}
		
		
	}
	
	private void userSetAttackTargetReq(MessageObject mo) {
		
		ClientToBattleServerPb.UserSetAttackTargetReq req = (UserSetAttackTargetReq)mo.getData();
		gameMap.setUnitAttackTarget(req.getId(), req.getAttackId());
		logger.debug("receive userSetAttackTargetReq");
	}
	
	
	
	private void saveCharacter(UserAgent agent) {
		BS2DBSaveCharacterReq.Builder saveBuilder = BS2DBSaveCharacterReq.newBuilder();
		DCharacterPb.Builder charBuilder = DCharacterPb.newBuilder();
		charBuilder.setId(agent.getCharId());
		charBuilder.setItemUidSeed(agent.getUidSeed());
		saveBuilder.setCharacter(charBuilder.build());
		DatabaseManager.getInstance().sendDbSaveCharacterReq(saveBuilder.build());
	}
	
	//处理玩家登出
	private void playerLogout(MessageObject mo){
		ClientToBattleServerPb.Logout req  = (Logout) mo.getData();
		//从房间数组移除
		int charId = req.getUserId();
		int gameId = 0;
		if (map.containsKey(charId)) {
			saveCharacter(map.get(charId));
			gameId = map.get(charId).getUnit().getId();
			map.remove(charId);
		}
		
		logger.debug("charId "+charId+" logout");
		//告知房间内的所有玩家这个玩家走了
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int otherCharId = it.next();
			UserAgent p = map.get(otherCharId);
			ClientToBattleServerPb.LogoutNotify.Builder builder = ClientToBattleServerPb.LogoutNotify.newBuilder();
			builder.setId(gameId);
			
			p.getSession().write(builder.build());
		}
		
		
	}
	
	/**
	 * 给客户端发广播，广播的一个基本准则是这样
	 * 如果A在移动，那么一定会把A周围的玩家广播给A（哪怕这些玩家没动，否则A如果靠近一个没动的B就看不见B了）
	 * 如果A没有移动，那么只会把A周围正在移动的玩家广播给A
	 * 对于每一个玩家，都作上述处理
	 * 
	 * 广播的内容包括
	 * 1.id
	 * 2.位置
	 * 3.状态
	 * 如果客户端收到的状态为1，则将此玩家移动到位置，如果收到的状态为0，则把此玩家setPosition()到此位置
	 * 
	 * 状态和位置由客户端不断的向服务器请求后在服务器端保存
	 */
	
	private void broadcast(){
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			//LinkedList<DistanceObject<GameObject>> list = gameMap.getObjectsInDistance(player.getUnit(), 10);
			
			//组装一条需要发给某个玩家的广播信息
			MoveNotify mn = null;
			if (player.getUnit().getState() != AiState.Move) {
				mn = getNearPlayer(player,map.keySet().iterator(),true);
			}
			else {
				mn = getNearPlayer(player,map.keySet().iterator(),false);
			}

			if(mn.getListCount()>0){
				player.getSession().write(mn);
			}
		}
	}
	private void broadcastToAll(){
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()){
			int id = it.next();
			UserAgent player = map.get(id);
			//组装一条需要发给某个玩家的广播信息
			MoveNotify mn = getNearPlayer(player,map.keySet().iterator(),false);
			if(mn.getListCount()>0){
				player.getSession().write(mn);
			}
		}
	}
	
	/**
	 * 获取一个玩家周围的其他玩家信息
	 * @param player
	 * @param list
	 * @param includeIdel是否忽略站立不动的玩家
	 */
	private MoveNotify getNearPlayer(UserAgent player,Iterator<Integer> it,boolean ignorIdle){
		MoveNotify.Builder mb = MoveNotify.newBuilder();
		while(it.hasNext()){
			int id = it.next();
			UserAgent other = map.get(id);
			if(other.getUnit().getId()!=player.getUnit().getId()){
				//如果不包含静止的，就要忽略静止的
				if(ignorIdle&&other.getUnit().getState()!=AiState.Move){
					continue;
				}
//				if(ignorIdle&&other.getMoveState()==0){
//					continue;
//				}
				MoveDataPb.Builder pmd = MoveDataPb.newBuilder();
				pmd.setId(other.getUnit().getId());
				if (other.getUnit().isMonster()) {
					pmd.setMoveEntityType(MoveEntityTypePb.MoveEntityType_Monster);
				}
				else {
					pmd.setMoveEntityType(MoveEntityTypePb.MoveEntityType_Player);
				}
				pmd.setPos(Vector3Helper.convertToDataprotoVector3(other.getUnit().getPosition()));
				if (other.getUnit().getState() == AiState.Move) {
					pmd.setState(1);
				}
				else {
					pmd.setState(0);
				}
				
				//pmd.setPos(other.getPos());
				//pmd.setState(other.getMoveState());
				mb.addList(pmd.build());
			}
		}
		return mb.build();
	}
}
